package com.lambkit.api.sign;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.crypto.digest.HmacAlgorithm;
import com.lambkit.util.Printer;

import javax.servlet.http.HttpServletRequest;
import java.util.Base64;

public class SignKit {
	
	public static Signature getSignature(HttpServletRequest request, String headerPrefix) {
		String id = request.getHeader(headerPrefix + "-ID");
		String key = request.getHeader(headerPrefix + "-KEY");
		String sign = request.getHeader(headerPrefix + "-SIGN");
		String time = request.getHeader(headerPrefix + "-TIME");
		
		Signature signature = new Signature();
		signature.setId(id);
		signature.setKey(key);
		signature.setDatetime(Long.valueOf(time));
		signature.setSign(sign);
		return signature;
	}
	
	public static Signature createSignature(String key, String id, String secret) {
		Signature signature = new Signature();
		signature.setId(id);
		signature.setKey(key);
		String sign = hmacSign(signature, secret);
		signature.setSign(sign);
		return signature;
	}
	
	public static Signature copySignature(HttpServletRequest request, String headerPrefix, String secret) {
		String id = request.getHeader(headerPrefix + "-ID");
		String key = request.getHeader(headerPrefix + "-KEY");
		String time = request.getHeader(headerPrefix + "-TIME");
		
		Signature signature = new Signature();
		signature.setId(id);
		signature.setKey(key);
		signature.setDatetime(Long.valueOf(time));
		String sign = hmacSign(signature, secret);
		signature.setSign(sign);
		return signature;
	}

	public static String hmacSign(Signature signature, String secret) {
		String content = signature.content(secret);
		byte[] key = base64ToBytes(secret);
		HMac mac = new HMac(HmacAlgorithm.HmacSHA256, key);
        //签名
		String signedStr = mac.digestHex(content);
        Printer.print(SignKit.class, "auth", "签名：" + signedStr);
        return signedStr;
	}
	
	public static boolean hmacVerify(Signature signature, String secret) {
		String content = signature.content(secret);
		byte[] key = base64ToBytes(secret);
		HMac mac = new HMac(HmacAlgorithm.HmacSHA256, key);
		String signedStr = mac.digestHex(content);
        return signedStr.equals(signature.getSign());
	}
	
	
	/**
	 * RSA签名
	 * @param signature
	 * @param secret 加密口令与密钥
	 * @param privateKeyStr
	 * @param privateKeyStr
	 * @return
	 * @throws Exception
	 */
	public static String sign(Signature signature, String secret, String privateKeyStr) {
		String content = signature.content(secret);
		Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, privateKeyStr, null);
        //签名
        byte[] data = content.getBytes(CharsetUtil.CHARSET_UTF_8);
        byte[] signed = sign.sign(data);
        String signedStr = bytesToBase64(signed);
        Printer.print(SignKit.class, "auth", "签名：" + signedStr);
        return signedStr;
	}

	/**
	 * RSA验签
	 * @param signature
	 * @param secret
	 * @param publicKeyStr
	 * @return
	 * @throws Exception
	 */
	public static boolean signVerify(Signature signature, String secret, String publicKeyStr) {
		String signedStr = signature.getSign();
		String content = signature.content(secret);
		byte[] data = content.getBytes(CharsetUtil.CHARSET_UTF_8);
		Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, null, publicKeyStr);
		//验证签名
        boolean verify = sign.verify(data, base64ToBytes(signedStr));
        Printer.print(SignKit.class, "auth", "验签：" + verify);
		return verify;
	}
	
	public static String rsaEncryptPublicKey(String content, String publicKeyStr) {
		RSA rsa = new RSA(null, publicKeyStr);
		//公钥加密，私钥解密
        byte[] encrypt = rsa.encrypt(StrUtil.bytes(content, CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey);
        String encryptStr = bytesToBase64(encrypt);
        Printer.print(SignKit.class, "auth", "公钥加密：" + encryptStr);
        return encryptStr;
	}
	
	public static String rsaDecryptPrivateKey(String content, String privateKeyStr) {
		RSA rsa = new RSA(privateKeyStr, null);
		byte[] encrypt = base64ToBytes(content);
		byte[] decrypt = rsa.decrypt(encrypt, KeyType.PrivateKey);
		String decryptStr = StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8);//new String(decrypt, Charset.forName("UTF-8"));
        Printer.print(SignKit.class, "auth", "私钥解密：" + decryptStr);
        return decryptStr;
	}
	
	public static String rsaEncryptPrivateKey(String content, String privateKeyStr) {
		RSA rsa = new RSA(privateKeyStr, null);
		//公钥加密，私钥解密
        byte[] encrypt = rsa.encrypt(StrUtil.bytes(content, CharsetUtil.CHARSET_UTF_8), KeyType.PrivateKey);
        String encryptStr = bytesToBase64(encrypt);
        Printer.print(SignKit.class, "auth", "公钥加密：" + encryptStr);
        return encryptStr;
	}
	
	public static String rsaDecryptPublicKey(String content, String publicKeyStr) {
		RSA rsa = new RSA(null, publicKeyStr);
		byte[] encrypt = base64ToBytes(content);
		byte[] decrypt = rsa.decrypt(encrypt, KeyType.PublicKey);
		String decryptStr = StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8);//new String(decrypt, Charset.forName("UTF-8"));
        Printer.print(SignKit.class, "auth", "私钥解密：" + decryptStr);
        return decryptStr;
	}
	/**
     * 字节数组转Base64编码
     *
     * @param bytes 字节数组
     * @return Base64编码
     */
    private static String bytesToBase64(byte[] bytes) {
        byte[] encodedBytes = Base64.getEncoder().encode(bytes);
        return StrUtil.str(encodedBytes, CharsetUtil.CHARSET_UTF_8);//new String(encodedBytes, Charset.forName("UTF-8"));
    }

    /**
     * Base64编码转字节数组
     *
     * @param base64Str Base64编码
     * @return 字节数组
     */
    private static byte[] base64ToBytes(String base64Str) {
        byte[] bytes = base64Str.getBytes(CharsetUtil.CHARSET_UTF_8);
        return Base64.getDecoder().decode(bytes);
    }
}
